/**
*
*/
package net.frontlinesms.data.repository.hibernate;
import java.util.List;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.springframework.transaction.annotation.Transactional;
import net.frontlinesms.data.DuplicateKeyException;
import net.frontlinesms.data.Order;
import net.frontlinesms.data.domain.Contact;
import net.frontlinesms.data.domain.Group;
import net.frontlinesms.data.repository.GroupDao;
/**
* Hibernate implementation of {@link GroupDao}.
* @author Alex Anderson <alex@frontlinesms.com>
* @author Morgan Belkadi <morgan@frontlinesms.com>
*/
public class HibernateGroupDao extends BaseHibernateDao<Group> implements GroupDao {
/** Create instance of this class */
public HibernateGroupDao() {
super(Group.class);
}
/** @see GroupDao#deleteGroup(Group, boolean) */
@Transactional
public void deleteGroup(Group group, boolean destroyContacts) {
// Dereference all keywordActions relating to this group
String keywordActionQuery = "DELETE FROM KeywordAction WHERE group_path=?";
super.getHibernateTemplate().bulkUpdate(keywordActionQuery, group.getPath());
Object[] paramValues = getPathParamValues(group);
if (destroyContacts) {
// If the contacts must also be destroyed, we start by selecting them
String queryString = "SELECT DISTINCT contact FROM GroupMembership WHERE group_path=? OR group_path LIKE ?";
List<Contact> contactsList = getList(Contact.class, queryString, paramValues);
// Then we delete all group memberships for the group and its descendants
String groupMembershipQuery = "DELETE from GroupMembership WHERE group_path=? OR group_path LIKE ?";
super.getHibernateTemplate().bulkUpdate(groupMembershipQuery, paramValues);
// Then, for each contact...
for (Contact c : contactsList) {
// We remove it from each group it's included in
groupMembershipQuery = "DELETE from GroupMembership WHERE contact=?";
super.getHibernateTemplate().bulkUpdate(groupMembershipQuery, c);
// And we delete the contact
String deleteContactQuery = "DELETE FROM Contact WHERE id=?";
super.getHibernateTemplate().bulkUpdate(deleteContactQuery, c.getId());
}
} else {
// We just delete all group memberships for the group and its descendants
String groupMembershipQuery = "DELETE from GroupMembership WHERE group_path=? OR group_path LIKE ?";
super.getHibernateTemplate().bulkUpdate(groupMembershipQuery, paramValues);
}
// Finally, we delete all child groups and the group itself
DetachedCriteria criteria = super.getCriterion();
Criterion equals = Restrictions.eq(Group.Field.PATH.getFieldName(), paramValues[0]);
Criterion like = Restrictions.like(Group.Field.PATH.getFieldName(), paramValues[1].toString(), MatchMode.START);
criteria.add(Restrictions.or(equals, like));
List<Group> groups = getList(criteria);
for (Group deletedGroup : groups) {
this.delete(deletedGroup);
}
}
/** @return params for matching this group and its children */
private Object[] getPathParamValues(Group group) {
String groupPath = group.getPath();
String childPath = groupPath + Group.PATH_SEPARATOR + "%";
return new Object[]{groupPath, childPath};
}
/** @see GroupDao#getAllGroups() */
public List<Group> getAllGroups() {
DetachedCriteria criteria = super.getSortCriterion(Group.Field.PATH, Order.ASCENDING);
return super.getList(criteria);
}
public boolean hasDescendants(Group parent) {
return super.getCount(getChildCriteria(parent)) > 0;
}
/** @see GroupDao#getChildGroups(Group) */
public List<Group> getChildGroups(Group parent) {
return super.getList(getChildCriteria(parent));
}
/** @see GroupDao#getAllGroups(int, int) */
public List<Group> getAllGroups(int startIndex, int limit) {
DetachedCriteria criteria = super.getSortCriterion(Group.Field.PATH, Order.ASCENDING);
return super.getList(criteria, startIndex, limit);
}
/** @see GroupDao#getGroupByPath(String) */
public Group getGroupByPath(String path) {
DetachedCriteria criteria = super.getCriterion();
criteria.add(Restrictions.eq(Group.Field.PATH.getFieldName(), path));
return super.getUnique(criteria);
}
/** @see GroupDao#getGroupCount() */
public int getGroupCount() {
return super.countAll();
}
/** @see GroupDao#saveGroup(Group) */
public void saveGroup(Group group) throws DuplicateKeyException {
super.save(group);
}
/** @see GroupDao#updateGroup(Group) */
public void updateGroup(Group group) {
super.updateWithoutDuplicateHandling(group);
}
/** @return criteria for getting the children of a group */
private DetachedCriteria getChildCriteria(Group parent) {
DetachedCriteria criteria = super.getSortCriterion(Group.Field.PATH, Order.ASCENDING);
// criteria.add(Restrictions.like(Group.Field.PATH.getFieldName(), parent.getPath() + Group.PATH_SEPARATOR + "[^" + Group.PATH_SEPARATOR + "]"));
criteria.add(Restrictions.eq("parentPath", parent.getPath()));
return criteria;
}
/**
* Gets a list of E matching the supplied HQL query.
* @param hqlQuery HQL query
* @param values values to insert into the HQL query
* @return a list of Es matching the supplied query
*/
@SuppressWarnings("unchecked")
protected <T> List<T> getList(Class<T> entityClass, String hqlQuery, Object... values) {
return this.getHibernateTemplate().find(hqlQuery, values);
}
}